The following is an implementation introduction for CALib.
The CALib API is modeled after the QuickTime APIs. The caller is required to check for it’s presence and avoid calling the API if it is not installed.
Motivation
The basic goal of CALib is to allow standard Macintosh applications to be easily modified to allow embedding of OpenDoc parts.
Goals
• Support C, Pascal and C++ apps.
• Provide a library with a procedural API which supports container application
behavior. Allow developers to ignore all of OpenDoc API, and possibly not have to support
NuRuntime.
• Make a part see being embedded in an application appear the same as being embedded
in a containing part.
• Minimize hit on code size of container application
Non-goals
• CALib support on non-OpenDoc system software.
• Support all OpenDoc functionality in container applications.
Requirements
A container application (CA) must be able to:
• Act like a simple containing part.
CAs must provide the basic functionality of containing parts. The difference should not be distinguishable to an embedded part. CAs don’t need to support all the frills, just the basics. For instance, a CA needn’t support negotiation for frame size. The support library will only provide for the required basics.
• Provide the simplest of the functionality presented by the OpenDoc Shell subsystem. They must create an OpenDoc runtime environment through CALib and connect it to the underlying application environment. CAs will manage their own UI events, drawing, storage, etc., but must cooperate with OpenDoc to coordinate with embedded parts.
• Embed multiple parts.
In all but the most rare cases, if a CA can embed one part, it should be able to embed any number of parts.
• Store data in a flat stream, i.e. a single storage unit value.
A CA does NOT need to:
• Provide a container suite.
• Provide a Bento handler.
• Modify & rebuild the CALib Proxy part for additional functionality
• Support Drag & Drop, Edition Manager, AOCE Mailer
A CA cannot:
• Use structured storage within a Bento container.
• Support OpenDoc features such as linking to native content, multiple drafts, etc.
Strategy
Apple will provide a library with a procedural API that application developers can use to enable embedding of parts. Internally, the CALib will create a proxy part to represent the root part of an application’s document. The Proxy part is provided as a part editor (although merged into one file with CALib), CALib is like a subsystem. Source to the CALib and Proxy part will be available to developers.
Embedding
A CA embeds parts/frames much like a containing part does. Each embedded part will be represented by a frame pointer (CAFrameRef) returned to the CA. These, however, can be treated as magic cookies and their behavior ignored. The CA need only save the CAFrameRef and an associated external transform (frame location). A CA may also store other information associated with each frame such as: the frame region, selection region information, etc.. All interaction with the frame or its part is through the CALib API.
Globals
CALib is implemented as a CFM library in the same fashion as the OpenDoc libraries. The underlying support for the library is implemented using several C++ objects. These provide support for the facilities provided by the OpenDoc Shell and the root Part in a standard OpenDoc session. These objects are allocated dynamically for each accessor of CALib. Several “global” variables are maintained by the Session API and are also allocated on a per-accessor basis.
Proxy root part
In the OpenDoc architecture, the root part of a document usually handles a lot of the document level operations such as Print, Page Setup, setting the size of windows etc. A CA handles these functions and others which are usually associated with the root part of a document. As a result, we find it helpful to introduce a proxy part. This root part uses the same part editor, as far the architecture is concerned, as every document for every container application does. There is one proxy part instance for each open CA document. This Proxy part also performs the following functions:
• Acts as the containing part for all parts embedded in content of the CA.
• Keeps track of the root frame's used region (area of a window used by embedded frames),
this allows clipping info to be communicated to the CA.
• Calls through to CA registered callbacks which handle various "Container" responsibilities, in
response to HandleEvent() and other ODPart methods.
Mailer Support
If the CA does not support the AOCE mailer, there is no issue, and OpenDoc will not support the AOCE mailer for it. If the CA wishes to support the AOCE mailer, then it must be responsible for keeping the ODContainer as a separate file while editing/viewing the contents, and streaming it to/from the main enclosure of the AOCE letter file when the user Opens, Saves and Closes the document.
Semantic Events
OpenDoc patches the CA's AppleEvent handlers. This requires the CA to register all of its Apple Event handlers before initializing CALib.
When a CA is doing object specifier resolution and it gets to a frame boundary, it needs to call:
CASwapToFrameRef(CADocumentRef, CAFrameRef);
Also, a CA must ignore the first four bytes of the datahandle of the token. These are used by OpenDoc.
Error Handling
CALib catches all errors returned from either the operating system, or OpenDoc. The actual error code is not returned to the caller as a result of any given subroutine call. Rather the CA implementor is required to check the result of each call to CALib using the CAError() function. This is similar to the use of ResError().
CASession
A CASession object is allocated for each active Container Application. The CASession object maintains CALib internal data structures and other state information.
CADocument Implementation
A CADocumentRef represents one of the following document types: a CA document, an OpenDoc part document, Clipboard or DragAndDrop. CALib allocates a CADocument subclass object for each working document. CADocument is a virtual base class, a subclass exists for each specific document type.
The CASession object maintains a list of CADocument objects for all active documents. For each open CA document a temporary ODContainer is allocated which contains the CAProxyPart draft. When a CA document is saved, the temporary container is externalized and a stream representation of the container is copied back to the CA.
A CA obtains CADocuments via CACreateDocument() and CAOpenDocument().
CAOpenDocument() is also used to open an OpenDoc Container document. The CA obtains CADocumentRef’s for the clipboard and dragdrop via CAGetClipboardDocument() and CAGetDragDropDocument().
CAFrameRef Implementation
For each embedded frame, the CA is given a CAFrameRef. A CAFrameRef is implemented internally as a strong storage unit reference derived from the first value in the CAProxyPart’s kODPropContents property. The CA stores CAFrameRef for later reference to embedded frames.